package cn.zcj.studytest.service;


import cn.zcj.studytest.ThrowData.Result;
import cn.zcj.studytest.domain.Lottery;
import cn.zcj.studytest.mapper.LotteryMapper;
import cn.zcj.studytest.vo.LotteryVO;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

@Slf4j
@Service
public class LotteryService extends ServiceImpl<LotteryMapper, Lottery> {
    @Resource
            private  LotteryMapper lotteryMapper;
    Result<Object> result = new Result<>();
    // 每次未中奖增加的weight值
    private static final int WEIGHT_INCREMENT = 20;
    // 默认初始weight
    private static final int DEFAULT_WEIGHT = 1;

    public Result<List<Lottery>> getLotteryName() {

        List<Lottery> lotteryList = this.list();

        // 3️⃣ 封装为统一返回结果
        return result.ok(lotteryList);
    }

    /**
     * 根据概率进行抽奖
     * @param count 抽奖人数
     * @return 中奖者列表
     * 
     * 抽奖逻辑：
     * 1. 根据每个人的 probability 概率进行加权随机抽奖
     * 2. 中奖者的 weight 保持不变
     * 3. 未中奖者的 weight 都加1
     * 4. 重新计算所有人的概率
     */
    public Result<List<Lottery>> awardWinner(int count) {
        // 1️⃣ 获取数据
        Result<List<Lottery>> result = getLotteryName();
        List<Lottery> lotteryList = result.getData();

        if (lotteryList == null || lotteryList.isEmpty()) {
            result.setMsg("没有抽奖数据");
            result.setSuccess(false);
            return result;
        }

        if (count <= 0 || count > lotteryList.size()) {
            result.setMsg("抽奖人数不合法");
            result.setSuccess(false);
            return result;
        }

        // 2️⃣ 计算 weight 总和
        int totalWeight = lotteryList.stream()
                .mapToInt(Lottery::getWeight)
                .sum();

        log.info("weight 总和为：{}", totalWeight);

        // 3️⃣ 计算每个人的概率，并设置到probability字段
        if (totalWeight > 0) {
            for (Lottery lottery : lotteryList) {
                // 保留两位小数
                double probability = Math.round(((double) lottery.getWeight() / (double) totalWeight * 10000.0)) / 100.0;
                log.info("【{}】当前 weight: {}, probability: {}%", lottery.getName(), lottery.getWeight(), probability);
                lottery.setProbability(probability);
            }
        }

        // 4️⃣ 根据概率进行抽奖
        List<Lottery> winners = new ArrayList<>();
        List<Lottery> candidates = new ArrayList<>(lotteryList);
        
        for (int i = 0; i < count; i++) {
            if (candidates.isEmpty()) {
                break;
            }
            
            // 根据 weight 进行加权随机抽奖
            Lottery winner = this.selectWinnerByWeight(candidates);
            winners.add(winner);
            
            // 从候选列表中移除中奖者，避免重复中奖
            candidates.remove(winner);
            
            log.info("第 {} 轮抽奖，中奖者：{}", i + 1, winner.getName());
        }

        // 5️⃣ 更新数据库：未中奖者的 weight 加1，中奖者的 weight 不变
        for (Lottery lottery : lotteryList) {
            if (!winners.contains(lottery)) {
                // 未中奖，weight 加1
                lottery.setWeight(lottery.getWeight() + WEIGHT_INCREMENT);
                log.info("【{}】未中奖，weight 更新为：{}", lottery.getName(), lottery.getWeight());
            } else {
                log.info("【{}】中奖，weight 保持不变：{}", lottery.getName(), lottery.getWeight());
            }
            this.lotteryMapper.updateById(lottery);
        }

        // 6️⃣ 重新计算所有人的概率
        int newTotalWeight = lotteryList.stream()
                .mapToInt(Lottery::getWeight)
                .sum();
        
        log.info("更新后的 weight 总和为：{}", newTotalWeight);
        
        for (Lottery lottery : lotteryList) {
            double newProbability = Math.round(((double) lottery.getWeight() / (double) newTotalWeight * 10000.0)) / 100.0;
            lottery.setProbability(newProbability);
            this.lotteryMapper.updateById(lottery);
            log.info("【{}】更新后的 probability: {}%", lottery.getName(), newProbability);
        }

        // 7️⃣ 返回中奖者列表
        return result.ok(winners);
    }

    /**
     * 根据 weight 进行加权随机选择
     * @param candidates 候选人列表
     * @return 中奖者
     */
    private Lottery selectWinnerByWeight(List<Lottery> candidates) {
        // 计算总权重
        int totalWeight = candidates.stream()
                .mapToInt(Lottery::getWeight)
                .sum();
        
        // 生成随机数 [0, totalWeight)
        Random random = new Random();
        int randomWeight = random.nextInt(totalWeight);
        
        // 根据权重选择中奖者
        int currentWeight = 0;
        for (Lottery lottery : candidates) {
            currentWeight += lottery.getWeight();
            if (randomWeight < currentWeight) {
                return lottery;
            }
        }
        
        // 理论上不会到这里，但为了安全返回最后一个
        return candidates.get(candidates.size() - 1);
    }

}
